<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>珠峰架构师成长计划</title>
    <link rel="stylesheet" type="text/css" href="../static/css/main.css">
</head>
<body>
<div class="nav">
    <div class="logo">
        
            珠峰架构师成长计划
        
    </div>
<ul><li><a href="../index.html">0.Async</a></li><li><a href="../html/0.editor.html">0.editor</a></li><li><a href="../html/0.module.html">0.module</a></li><li><a href="../html/1.ES2015.html">1.ES2015</a></li><li><a href="../html/2.Promise.html">2.Promise</a></li><li><a href="../html/3.Node.html">3.Node</a></li><li><a href="../html/4.NodeInstall.html">4.NodeInstall</a></li><li><a href="../html/5.REPL.html">5.REPL</a></li><li><a href="../html/6.NodeCore.html">6.NodeCore</a></li><li><a href="../html/7.module&NPM.html">7.module&NPM</a></li><li><a href="../html/8.Encoding.html">8.Encoding</a></li><li><a href="../html/9.Buffer.html">9.Buffer</a></li><li><a href="../html/10.fs.html">10.fs</a></li><li><a href="../html/11.Stream-1.html">11.Stream-1</a></li><li><a href="../html/11.Stream-2.html">11.Stream-2</a></li><li><a href="../html/11.Stream-3.html">11.Stream-3</a></li><li><a href="../html/11.Stream-4.html">11.Stream-4</a></li><li><a href="../html/12-Network-2.html">12-Network-2</a></li><li><a href="../html/12.NetWork-3.html">12.NetWork-3</a></li><li><a href="../html/12.Network-1.html">12.Network-1</a></li><li><a href="../html/13.tcp.html">13.tcp</a></li><li><a href="../html/14.http-1.html">14.http-1</a></li><li><a href="../html/14.http-2.html">14.http-2</a></li><li><a href="../html/15.compress.html">15.compress</a></li><li><a href="../html/16.crypto.html">16.crypto</a></li><li><a href="../html/17.process.html">17.process</a></li><li><a href="../html/18.yargs.html">18.yargs</a></li><li><a href="../html/19.cache.html">19.cache</a></li><li><a href="../html/20.action.html">20.action</a></li><li><a href="../html/21.https.html">21.https</a></li><li><a href="../html/22.cookie.html">22.cookie</a></li><li><a href="../html/23.session.html">23.session</a></li><li><a href="../html/24.express-1.html">24.express-1</a></li><li><a href="../html/24.express-2.html">24.express-2</a></li><li><a href="../html/24.express-3.html">24.express-3</a></li><li><a href="../html/24.express-4.html">24.express-4</a></li><li><a href="../html/25.koa-1.html">25.koa-1</a></li><li><a href="../html/26.webpack-1-basic.html">26.webpack-1-basic</a></li><li><a href="../html/26.webpack-2-optimize.html">26.webpack-2-optimize</a></li><li><a href="../html/26.webpack-3.tapable.html">26.webpack-3.tapable</a></li><li><a href="../html/26.webpack-4-AST.html">26.webpack-4-AST</a></li><li><a href="../html/26.webpack-5-source.html">26.webpack-5-source</a></li><li><a href="../html/26.webpack-6-loader.html">26.webpack-6-loader</a></li><li><a href="../html/26.webpack-7-plugin.html">26.webpack-7-plugin</a></li><li><a href="../html/26.webpack-8-hand.html">26.webpack-8-hand</a></li><li><a href="../html/27.react-1.html">27.react-1</a></li><li><a href="../html/27.react-2.html">27.react-2</a></li><li><a href="../html/27.react-3.html">27.react-3</a></li><li><a href="../html/27.react-4-immutable.html">27.react-4-immutable</a></li><li><a href="../html/27.react-5-react-dom-diff.html">27.react-5-react-dom-diff</a></li><li><a href="../html/27.react-6.html">27.react-6</a></li><li><a href="../html/28.react-mobx.html">28.react-mobx</a></li><li><a href="../html/28.redux-0.html">28.redux-0</a></li><li><a href="../html/28.redux-1.html">28.redux-1</a></li><li><a href="../html/28.redux-2-中间件.html">28.redux-2-中间件</a></li><li><a href="../html/28.redux-3-saga.html">28.redux-3-saga</a></li><li><a href="../html/28.redux-jwt-back.html">28.redux-jwt-back</a></li><li><a href="../html/28.redux-jwt-front.html">28.redux-jwt-front</a></li><li><a href="../html/29.mongodb-1.html">29.mongodb-1</a></li><li><a href="../html/29.mongodb-2.html">29.mongodb-2</a></li><li><a href="../html/29.mongodb-3.html">29.mongodb-3</a></li><li><a href="../html/29.mongodb-4.html">29.mongodb-4</a></li><li><a href="../html/29.mongodb-5.html">29.mongodb-5</a></li><li><a href="../html/29.mongodb-6.html">29.mongodb-6</a></li><li><a href="../html/30.cms-1-mysql.html">30.cms-1-mysql</a></li><li><a href="../html/30.cms-2-mysql.html">30.cms-2-mysql</a></li><li><a href="../html/30.cms-3-mysql.html">30.cms-3-mysql</a></li><li><a href="../html/30.cms-4-egg.html">30.cms-4-egg</a></li><li><a href="../html/30.cms-5-api.html">30.cms-5-api</a></li><li><a href="../html/30.cms-6-roadhog.html">30.cms-6-roadhog</a></li><li><a href="../html/30.cms-7-umi.html">30.cms-7-umi</a></li><li><a href="../html/30.cms-8-dva.html">30.cms-8-dva</a></li><li><a href="../html/30.cms-9-dva.html">30.cms-9-dva</a></li><li><a href="../html/30.cms-10-front.html">30.cms-10-front</a></li><li><a href="../html/30.cms-11-deploy.html">30.cms-11-deploy</a></li><li><a href="../html/33.redis.html">33.redis</a></li><li><a href="../html/34.unittest.html">34.unittest</a></li><li><a href="../html/35.jwt.html">35.jwt</a></li><li><a href="../html/36.websocket-1.html">36.websocket-1</a></li><li><a href="../html/36.websocket-2.html">36.websocket-2</a></li><li><a href="../html/38.chat-api-1.html">38.chat-api-1</a></li><li><a href="../html/38.chat-api-2.html">38.chat-api-2</a></li><li><a href="../html/38.chat-3.html">38.chat-3</a></li><li><a href="../html/38.chat-api-3.html">38.chat-api-3</a></li><li><a href="../html/38.chat.html">38.chat</a></li><li><a href="../html/38.chat2.html">38.chat2</a></li><li><a href="../html/38.chat2.html">38.chat2</a></li><li><a href="../html/39.crawl-0.html">39.crawl-0</a></li><li><a href="../html/39.crawl-1.html">39.crawl-1</a></li><li class="active"><a href="../html/39.crawl-2.html">39.crawl-2</a></li><li><a href="../html/40.deploy.html">40.deploy</a></li><li><a href="../html/41.safe.html">41.safe</a></li><li><a href="../html/42.test.html">42.test</a></li><li><a href="../html/43.nginx.html">43.nginx</a></li><li><a href="../html/44.enzyme.html">44.enzyme</a></li><li><a href="../html/45.docker.html">45.docker</a></li><li><a href="../html/46.elastic.html">46.elastic</a></li><li><a href="../html/47.oauth.html">47.oauth</a></li><li><a href="../html/48.wxpay.html">48.wxpay</a></li><li><a href="../html/49.nunjucks.html">49.nunjucks</a></li><li><a href="../html/50.ketang.html">50.ketang</a></li><li><a href="../html/index.html">index</a></li><li><a href="../html/51.typescript.html">51.typescript</a></li><li><a href="../html/52.UML.html">52.UML</a></li><li><a href="../html/53.design.html">53.design</a></li><li><a href="../html/index.html">index</a></li><li><a href="../html/54.linux.html">54.linux</a></li><li><a href="../html/55.yaml.html">55.yaml</a></li><li><a href="../html/50.ketang2.html">50.ketang2</a></li><li><a href="../html/56.ts.html">56.ts</a></li><li><a href="../html/57.ts_react.html">57.ts_react</a></li><li><a href="../html/58.react-ssr.html">58.react-ssr</a></li><li><a href="../html/59.react-ssr.html">59.react-ssr</a></li></ul></div>


<div class="warpper">

    <div class="page-toc">
        <ul><li><a href="#t01.抓取数据">1.抓取数据</a><ul><li><a href="#t11.1 获取标签列表">1.1 获取标签列表</a></li><li><a href="#t21.2.文章列表">1.2.文章列表</a></li><li><a href="#t31.3.文章详情">1.3.文章详情</a></li><li><a href="#t41.4 入口任务">1.4 入口任务</a></li></ul></li><li><a href="#t52 表结构">2 表结构</a><ul><li><a href="#t62.1 tag(标签表)">2.1 tag(标签表)</a></li><li><a href="#t72.2 articles(文章表)">2.2 articles(文章表)</a></li><li><a href="#t82.3 article_tag(文章标签表)">2.3 article_tag(文章标签表)</a></li></ul></li><li><a href="#t93. 写入数据库">3. 写入数据库</a><ul><li><a href="#t103.1 写入标签">3.1 写入标签</a></li><li><a href="#t113.2 写入文章">3.2 写入文章</a></li></ul></li><li><a href="#t124. 建立web服务器查看数据">4. 建立web服务器查看数据</a><ul><li><a href="#t134.1 server.js">4.1 server.js</a></li><li><a href="#t144.2 index.html">4.2 index.html</a></li><li><a href="#t154.3 detail.html">4.3 detail.html</a></li><li><a href="#t164.4 header.html">4.4 header.html</a></li><li><a href="#t174.5 footer.html">4.5 footer.html</a></li><li><a href="#t184.6 login.html">4.6 login.html</a></li><li><a href="#t194.7 subscribe.html">4.7 subscribe.html</a></li></ul></li><li><a href="#t205. 订阅发布">5. 订阅发布</a><ul><li><a href="#t215.1 web/server.js">5.1 web/server.js</a></li><li><a href="#t225.2 fromCodePoint">5.2 fromCodePoint</a></li></ul></li></ul>
    </div>
    
    <div class="content markdown-body">
        <h2 id="t01.&#x6293;&#x53D6;&#x6570;&#x636E;">1.&#x6293;&#x53D6;&#x6570;&#x636E; <a href="#t01.&#x6293;&#x53D6;&#x6570;&#x636E;"> # </a></h2>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> request=<span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;request-promise&apos;</span>);
<span class="hljs-keyword">const</span> cheerio=<span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;cheerio&apos;</span>);
<span class="hljs-keyword">const</span> debug=<span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;debug&apos;</span>)(<span class="hljs-string">&apos;juejin:task:read&apos;</span>);
</code></pre>
<h3 id="t11.1 &#x83B7;&#x53D6;&#x6807;&#x7B7E;&#x5217;&#x8868;">1.1 &#x83B7;&#x53D6;&#x6807;&#x7B7E;&#x5217;&#x8868; <a href="#t11.1 &#x83B7;&#x53D6;&#x6807;&#x7B7E;&#x5217;&#x8868;"> # </a></h3>
<pre><code class="lang-js">exports.tagList=<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">uri</span>) </span>{
    debug(<span class="hljs-string">&apos;&#x8BFB;&#x53D6;&#x6587;&#x7AE0;&#x6807;&#x7B7E;&#x5217;&#x8868;&apos;</span>);
    <span class="hljs-keyword">let</span> options={
        uri,
        <span class="hljs-attr">transform</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">body</span>) </span>{
            <span class="hljs-keyword">return</span> cheerio.load(body);
        }
    }
    <span class="hljs-keyword">return</span> request(options).then(<span class="hljs-function"><span class="hljs-params">$</span> =&gt;</span> {
            <span class="hljs-keyword">let</span> tags= [];
            $(<span class="hljs-string">&apos;.item&apos;</span>).each(<span class="hljs-function">(<span class="hljs-params">i,item</span>) =&gt;</span> {
                <span class="hljs-keyword">let</span> tag=$(item);
                <span class="hljs-keyword">let</span> image=tag.find(<span class="hljs-string">&apos;div.thumb&apos;</span>).first();
                <span class="hljs-keyword">let</span> title=tag.find(<span class="hljs-string">&apos;.title&apos;</span>).first();
                <span class="hljs-keyword">let</span> subscribe=tag.find(<span class="hljs-string">&apos;.subscribe&apos;</span>).first();
                <span class="hljs-keyword">let</span> article=tag.find(<span class="hljs-string">&apos;.article&apos;</span>).first();
                <span class="hljs-keyword">let</span> name=title.text().trim();
                tags.push({
                    <span class="hljs-attr">image</span>: image.data(<span class="hljs-string">&apos;src&apos;</span>).trim(),
                    name,
                    <span class="hljs-attr">url</span>:<span class="hljs-string">`https://juejin.im/tag/<span class="hljs-subst">${<span class="hljs-built_in">encodeURIComponent</span>(title.text().trim())}</span>`</span>,
                    <span class="hljs-attr">subscribe</span>: <span class="hljs-built_in">Number</span>(subscribe.text().match(<span class="hljs-regexp">/(\d+)/</span>)[<span class="hljs-number">1</span>]),
                    <span class="hljs-attr">article</span>:<span class="hljs-built_in">Number</span>(article.text().match(<span class="hljs-regexp">/(\d+)/</span>)[<span class="hljs-number">1</span>])
                });
                debug(<span class="hljs-string">`&#x8BFB;&#x53D6;&#x6587;&#x7AE0;&#x6807;&#x7B7E;:<span class="hljs-subst">${name}</span>`</span>);
            });
           <span class="hljs-keyword">return</span> tags.slice(<span class="hljs-number">0</span>,<span class="hljs-number">1</span>);
    });
}
</code></pre>
<h3 id="t21.2.&#x6587;&#x7AE0;&#x5217;&#x8868;">1.2.&#x6587;&#x7AE0;&#x5217;&#x8868; <a href="#t21.2.&#x6587;&#x7AE0;&#x5217;&#x8868;"> # </a></h3>
<pre><code class="lang-js">exports.articleList=<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">uri</span>) </span>{
    debug(<span class="hljs-string">&apos;&#x8BFB;&#x53D6;&#x535A;&#x6587;&#x5217;&#x8868;&apos;</span>);
    <span class="hljs-keyword">let</span> options={
        uri,
        <span class="hljs-attr">transform</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">body</span>) </span>{
            <span class="hljs-keyword">return</span> cheerio.load(body);
        }
    }
    <span class="hljs-keyword">return</span> request(options).then(<span class="hljs-keyword">async</span> $ =&gt; {
        <span class="hljs-keyword">let</span> articleList=[];
        <span class="hljs-keyword">let</span> items =$(<span class="hljs-string">&apos;.item .title&apos;</span>);
        <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i=<span class="hljs-number">0</span>;i&lt;items.length;i++) {
            <span class="hljs-keyword">let</span> article=$(items[i]);
            <span class="hljs-keyword">let</span> href = article.attr(<span class="hljs-string">&apos;href&apos;</span>).trim();
            <span class="hljs-keyword">let</span> title=article.text().trim();
            <span class="hljs-keyword">let</span> id=href.match(<span class="hljs-regexp">/\/(\w+)$/</span>)[<span class="hljs-number">1</span>];
            href=<span class="hljs-string">&apos;https://juejin.im&apos;</span>+href;
            <span class="hljs-keyword">let</span> articleDetail = <span class="hljs-keyword">await</span> readArticle(id,href);
            articleList.push({
                href,
                title,
                id,
                <span class="hljs-attr">content</span>:articleDetail.content,
                <span class="hljs-attr">tags</span>:articleDetail.tags
            });
            debug(<span class="hljs-string">`&#x8BFB;&#x53D6;&#x6587;&#x7AE0;&#x5217;&#x8868;:<span class="hljs-subst">${title}</span>`</span>);
        }
        <span class="hljs-keyword">return</span> articleList;
    });
}
</code></pre>
<h3 id="t31.3.&#x6587;&#x7AE0;&#x8BE6;&#x60C5;">1.3.&#x6587;&#x7AE0;&#x8BE6;&#x60C5; <a href="#t31.3.&#x6587;&#x7AE0;&#x8BE6;&#x60C5;"> # </a></h3>
<pre><code class="lang-js"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">readArticle</span>(<span class="hljs-params">id,uri</span>) </span>{
    debug(<span class="hljs-string">&apos;&#x8BFB;&#x53D6;&#x535A;&#x6587;&apos;</span>);
    <span class="hljs-keyword">let</span> options={
        uri,
        <span class="hljs-attr">transform</span>: <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">body</span>) </span>{
            <span class="hljs-keyword">return</span> cheerio.load(body);
        }
    }
    <span class="hljs-keyword">return</span> request(options).then(<span class="hljs-function"><span class="hljs-params">$</span> =&gt;</span> {
        <span class="hljs-keyword">let</span> article=$(<span class="hljs-string">&apos;.main-container&apos;</span>);
        <span class="hljs-keyword">let</span> title=article.find(<span class="hljs-string">&apos;h1&apos;</span>).text().trim();
        <span class="hljs-keyword">let</span> content=article.find(<span class="hljs-string">&apos;.article-content&apos;</span>).html();
        <span class="hljs-keyword">let</span> tags=article.find(<span class="hljs-string">&apos;.tag-list-box&gt;div.tag-list&gt;a.item&apos;</span>);
        tags=tags.map(<span class="hljs-function">(<span class="hljs-params">index,item</span>) =&gt;</span> {
            <span class="hljs-keyword">let</span> href = $(item).attr(<span class="hljs-string">&apos;href&apos;</span>);
            <span class="hljs-keyword">return</span> href? href.slice(<span class="hljs-number">4</span>):href;
        })
        tags=<span class="hljs-built_in">Array</span>.prototype.slice.call(tags);
        debug(<span class="hljs-string">`&#x8BFB;&#x53D6;&#x6587;&#x7AE0;&#x8BE6;&#x60C5;:<span class="hljs-subst">${title}</span>`</span>);
        <span class="hljs-keyword">return</span> {
            id,
            title,
            content,
            tags
        };
    });
}
</code></pre>
<h3 id="t41.4 &#x5165;&#x53E3;&#x4EFB;&#x52A1;">1.4 &#x5165;&#x53E3;&#x4EFB;&#x52A1; <a href="#t41.4 &#x5165;&#x53E3;&#x4EFB;&#x52A1;"> # </a></h3>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> read = <span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;./read&apos;</span>);
<span class="hljs-keyword">let</span> write = <span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;./write&apos;</span>);
(<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">let</span> tagUrl = <span class="hljs-string">&apos;https://juejin.im/subscribe/all&apos;</span>;
    <span class="hljs-comment">//&#x8BFB;&#x53D6;&#x6398;&#x91D1;&#x7684;&#x6807;&#x7B7E;&#x5217;&#x8868;</span>
    <span class="hljs-keyword">let</span> tags = <span class="hljs-keyword">await</span> read.tags(tagUrl);
    <span class="hljs-comment">//&#x628A;&#x6807;&#x7B7E;&#x5199;&#x5230;&#x6570;&#x636E;&#x5E93;&#x4E2D;</span>
    <span class="hljs-keyword">await</span> write.tags(tags);
    <span class="hljs-keyword">let</span> allAricles = {};
    <span class="hljs-comment">//&#x6807;&#x7B7E;&#x6709;&#x5F88;&#x591A;&#xFF0C;&#x4E0D;&#x540C;&#x7684;&#x6807;&#x7B7E;&#x4E0B;&#x9762;&#x7684;&#x6587;&#x7AE0;&#x53EF;&#x80FD;&#x4F1A;&#x91CD;&#x590D;</span>
    <span class="hljs-keyword">for</span> (tag <span class="hljs-keyword">of</span> tags) {
        <span class="hljs-keyword">let</span> articles = <span class="hljs-keyword">await</span> read.articleList(tag.href);
        articles.forEach(<span class="hljs-function"><span class="hljs-params">article</span> =&gt;</span> allAricles[article.id] = article);
    }
    <span class="hljs-comment">// {id:article}</span>
    <span class="hljs-keyword">await</span> write.articles(<span class="hljs-built_in">Object</span>.values(allAricles));
    process.exit();
})()
</code></pre>
<h2 id="t52 &#x8868;&#x7ED3;&#x6784;">2 &#x8868;&#x7ED3;&#x6784; <a href="#t52 &#x8868;&#x7ED3;&#x6784;"> # </a></h2>
<h3 id="t62.1 tag(&#x6807;&#x7B7E;&#x8868;)">2.1 tag(&#x6807;&#x7B7E;&#x8868;) <a href="#t62.1 tag(&#x6807;&#x7B7E;&#x8868;)"> # </a></h3>
<table>
<thead>
<tr>
<th style="text-align:left">&#x5B57;&#x6BB5;</th>
<th style="text-align:left">&#x7C7B;&#x578B;</th>
<th style="text-align:left">&#x8BF4;&#x660E;</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">id</td>
<td style="text-align:left">int(11)</td>
<td style="text-align:left">&#x6807;&#x7B7E;&#x540D;&#x79F0;</td>
</tr>
<tr>
<td style="text-align:left">name</td>
<td style="text-align:left">varchar(255)</td>
<td style="text-align:left">&#x6807;&#x7B7E;&#x540D;&#x79F0;</td>
</tr>
<tr>
<td style="text-align:left">image</td>
<td style="text-align:left">varchar(255)</td>
<td style="text-align:left">&#x6807;&#x7B7E;&#x56FE;&#x7247;</td>
</tr>
<tr>
<td style="text-align:left">url</td>
<td style="text-align:left">varchar(255)</td>
<td style="text-align:left">url&#x5730;&#x5740;</td>
</tr>
<tr>
<td style="text-align:left">subscribe</td>
<td style="text-align:left">int(11)</td>
<td style="text-align:left">&#x8BA2;&#x9605;&#x6570;</td>
</tr>
<tr>
<td style="text-align:left">article</td>
<td style="text-align:left">int(11)</td>
<td style="text-align:left">&#x6587;&#x7AE0;&#x6570;</td>
</tr>
</tbody>
</table>
<pre><code class="lang-sql">+<span class="hljs-comment">-----------+--------------+------+-----+---------+----------------+</span>
| Field     | Type         | Null | Key | Default | Extra          |
+<span class="hljs-comment">-----------+--------------+------+-----+---------+----------------+</span>
| id        | int(11)      | NO   | PRI | NULL    | auto_increment |
| name      | varchar(255) | NO   |     | NULL    |                |
| image     | varchar(255) | NO   |     | NULL    |                |
| url       | varchar(255) | NO   |     | NULL    |                |
| subscribe | int(11)      | YES  |     | NULL    |                |
| article   | int(11)      | YES  |     | NULL    |                |
+<span class="hljs-comment">-----------+--------------+------+-----+---------+----------------+</span>
</code></pre>
<h3 id="t72.2 articles(&#x6587;&#x7AE0;&#x8868;)">2.2 articles(&#x6587;&#x7AE0;&#x8868;) <a href="#t72.2 articles(&#x6587;&#x7AE0;&#x8868;)"> # </a></h3>
<table>
<thead>
<tr>
<th style="text-align:left">&#x5B57;&#x6BB5;</th>
<th style="text-align:left">&#x7C7B;&#x578B;</th>
<th style="text-align:left">&#x8BF4;&#x660E;</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">id</td>
<td style="text-align:left">varchar(255)</td>
<td style="text-align:left">&#x6587;&#x7AE0;ID</td>
</tr>
<tr>
<td style="text-align:left">title</td>
<td style="text-align:left">varchar(255)</td>
<td style="text-align:left">&#x6587;&#x7AE0;&#x540D;&#x79F0;</td>
</tr>
<tr>
<td style="text-align:left">href</td>
<td style="text-align:left">varchar(255)</td>
<td style="text-align:left">&#x6587;&#x7AE0;&#x8FDE;&#x63A5;</td>
</tr>
<tr>
<td style="text-align:left">content</td>
<td style="text-align:left">longtext</td>
<td style="text-align:left">&#x6587;&#x7AE0;&#x5185;&#x5BB9;</td>
</tr>
</tbody>
</table>
<pre><code class="lang-sql">+<span class="hljs-comment">---------+--------------+------+-----+---------+-------+</span>
| Field   | Type         | Null | Key | Default | Extra |
+<span class="hljs-comment">---------+--------------+------+-----+---------+-------+</span>
| id      | varchar(255) | NO   | PRI | NULL    |       |
| title   | varchar(255) | NO   |     | NULL    |       |
| content | longtext     | YES  |     | NULL    |       |
| href    | varchar(255) | YES  |     | NULL    |       |
+<span class="hljs-comment">---------+--------------+------+-----+---------+-------+</span>
</code></pre>
<h3 id="t82.3 article_tag(&#x6587;&#x7AE0;&#x6807;&#x7B7E;&#x8868;)">2.3 article_tag(&#x6587;&#x7AE0;&#x6807;&#x7B7E;&#x8868;) <a href="#t82.3 article_tag(&#x6587;&#x7AE0;&#x6807;&#x7B7E;&#x8868;)"> # </a></h3>
<table>
<thead>
<tr>
<th style="text-align:left">&#x5B57;&#x6BB5;</th>
<th style="text-align:left">&#x7C7B;&#x578B;</th>
<th style="text-align:left">&#x8BF4;&#x660E;</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">article_id</td>
<td style="text-align:left">varchar(255)</td>
<td style="text-align:left">&#x6587;&#x7AE0;ID</td>
</tr>
<tr>
<td style="text-align:left">tag_id</td>
<td style="text-align:left">int(11)</td>
<td style="text-align:left">&#x6807;&#x7B7E;ID</td>
</tr>
</tbody>
</table>
<pre><code class="lang-sql">+<span class="hljs-comment">------------+--------------+------+-----+---------+-------+</span>
| Field      | Type         | Null | Key | Default | Extra |
+<span class="hljs-comment">------------+--------------+------+-----+---------+-------+</span>
| article_id | varchar(255) | NO   | PRI | NULL    |       |
| tag_id     | int(11)      | NO   | PRI | NULL    |       |
+<span class="hljs-comment">------------+--------------+------+-----+---------+-------+</span>
</code></pre>
<h2 id="t93. &#x5199;&#x5165;&#x6570;&#x636E;&#x5E93;">3. &#x5199;&#x5165;&#x6570;&#x636E;&#x5E93; <a href="#t93. &#x5199;&#x5165;&#x6570;&#x636E;&#x5E93;"> # </a></h2>
<p>db.js</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> mysql=<span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;mysql&apos;</span>);
<span class="hljs-keyword">var</span> <span class="hljs-built_in">Promise</span> = <span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;bluebird&apos;</span>);
<span class="hljs-keyword">const</span> connection = mysql.createConnection({
    <span class="hljs-attr">host</span>:            <span class="hljs-string">&apos;127.0.0.1&apos;</span>,   <span class="hljs-comment">// &#x6570;&#x636E;&#x5E93;&#x5730;&#x5740;</span>
    port:            <span class="hljs-number">3306</span>,          <span class="hljs-comment">// &#x6570;&#x636E;&#x5E93;&#x7AEF;&#x53E3;</span>
    database:        <span class="hljs-string">&apos;juejin&apos;</span>,   <span class="hljs-comment">// &#x6570;&#x636E;&#x5E93;&#x540D;&#x79F0;</span>
    user:            <span class="hljs-string">&apos;root&apos;</span>,        <span class="hljs-comment">// &#x6570;&#x636E;&#x5E93;&#x7528;&#x6237;</span>
    password:        <span class="hljs-string">&apos;&apos;</span>             <span class="hljs-comment">// &#x6570;&#x636E;&#x5E93;&#x7528;&#x6237;&#x5BF9;&#x5E94;&#x7684;&#x5BC6;&#x7801;</span>
});
connection.connect();
<span class="hljs-built_in">module</span>.exports={
    <span class="hljs-attr">query</span>:<span class="hljs-built_in">Promise</span>.promisify(connection.query).bind(connection),
    <span class="hljs-attr">end</span>:connection.end
}
</code></pre>
<p>crawl/task/write.js</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> {query,end}=<span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;../db&apos;</span>);
<span class="hljs-keyword">const</span> debug=<span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;debug&apos;</span>)(<span class="hljs-string">&apos;juejin:task:write&apos;</span>);
</code></pre>
<h3 id="t103.1 &#x5199;&#x5165;&#x6807;&#x7B7E;">3.1 &#x5199;&#x5165;&#x6807;&#x7B7E; <a href="#t103.1 &#x5199;&#x5165;&#x6807;&#x7B7E;"> # </a></h3>
<pre><code class="lang-js">exports.tagList=<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">tagList</span>) </span>{
    debug(<span class="hljs-string">&apos;&#x4FDD;&#x5B58;&#x6587;&#x7AE0;&#x6807;&#x7B7E;&#x5217;&#x8868;&apos;</span>);
    <span class="hljs-keyword">for</span> (tag <span class="hljs-keyword">of</span> tagList) {
        <span class="hljs-keyword">let</span> oldTags=<span class="hljs-keyword">await</span> query(<span class="hljs-string">`SELECT 1 FROM tags WHERE name=? LIMIT 1 `</span>,[tag.name]);
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.isArray(oldTags)&amp;&amp;oldTags.length&gt;<span class="hljs-number">0</span>) {
            <span class="hljs-keyword">let</span> oldTag=oldTags[<span class="hljs-number">0</span>];
            <span class="hljs-keyword">await</span> query(<span class="hljs-string">`UPDATE tags SET name=?,image=?,url=? WHERE id=?`</span>,[tag.name,tag.image,tag.url,oldTag.id]);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">await</span> query(<span class="hljs-string">`INSERT INTO tags(name,image,url) VALUES(?,?,?)`</span>,[tag.name,tag.image,tag.url]);
        }
    }
}
</code></pre>
<h3 id="t113.2 &#x5199;&#x5165;&#x6587;&#x7AE0;">3.2 &#x5199;&#x5165;&#x6587;&#x7AE0; <a href="#t113.2 &#x5199;&#x5165;&#x6587;&#x7AE0;"> # </a></h3>
<pre><code class="lang-js">
exports.articleList=<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">articleList</span>) </span>{
    debug(<span class="hljs-string">&apos;&#x5199;&#x5165;&#x535A;&#x6587;&#x5217;&#x8868;&apos;</span>);
    <span class="hljs-keyword">debugger</span>;
    <span class="hljs-keyword">for</span> (article <span class="hljs-keyword">of</span> articleList) {
        <span class="hljs-keyword">let</span> oldArticles = <span class="hljs-keyword">await</span>  query(<span class="hljs-string">`SELECT 1 FROM articles WHERE id=? LIMIT 1 `</span>,article.id);
        <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.isArray(oldArticles)&amp;&amp;oldArticles.length&gt;<span class="hljs-number">0</span>) {
            <span class="hljs-keyword">let</span> oldArticle=oldArticles[<span class="hljs-number">0</span>];
            <span class="hljs-keyword">await</span> query(<span class="hljs-string">`UPDATE articles SET title=?,content=?,href=? WHERE id=?`</span>,[article.title,article.content,article.href,oldArticle.id]);
        } <span class="hljs-keyword">else</span> {
            <span class="hljs-keyword">await</span> query(<span class="hljs-string">`INSERT INTO articles(id,title,href,content) VALUES(?,?,?,?)`</span>,[article.id,article.title,article.href,article.content]);
        }
        <span class="hljs-keyword">await</span> query(<span class="hljs-string">`DELETE FROM article_tag WHERE article_id=? `</span>,[article.id]);
        <span class="hljs-keyword">const</span> where=<span class="hljs-string">&quot;(&apos;&quot;</span>+article.tags.join(<span class="hljs-string">&quot;&apos;,&apos;&quot;</span>)+<span class="hljs-string">&quot;&apos;)&quot;</span>;
        <span class="hljs-keyword">const</span> sql=<span class="hljs-string">`SELECT id FROM tags WHERE name IN <span class="hljs-subst">${where}</span>`</span>;
        <span class="hljs-keyword">let</span> tagIds = <span class="hljs-keyword">await</span> query(sql);
        <span class="hljs-keyword">for</span> (row <span class="hljs-keyword">of</span> tagIds) {
            <span class="hljs-keyword">await</span> query(<span class="hljs-string">`INSERT INTO article_tag(article_id,tag_id) VALUES(?,?)`</span>,[article.id,row.id]);
        }
    }
}
</code></pre>
<h2 id="t124. &#x5EFA;&#x7ACB;web&#x670D;&#x52A1;&#x5668;&#x67E5;&#x770B;&#x6570;&#x636E;">4. &#x5EFA;&#x7ACB;web&#x670D;&#x52A1;&#x5668;&#x67E5;&#x770B;&#x6570;&#x636E; <a href="#t124. &#x5EFA;&#x7ACB;web&#x670D;&#x52A1;&#x5668;&#x67E5;&#x770B;&#x6570;&#x636E;"> # </a></h2>
<h3 id="t134.1 server.js">4.1 server.js <a href="#t134.1 server.js"> # </a></h3>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> express=<span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;express&apos;</span>);
<span class="hljs-keyword">const</span> path=<span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;path&apos;</span>);
<span class="hljs-keyword">const</span> {query}=<span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;../db&apos;</span>);
<span class="hljs-keyword">const</span> cronJob=<span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;cron&apos;</span>).CronJob;
<span class="hljs-keyword">const</span> debug=<span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;debug&apos;</span>)(<span class="hljs-string">&apos;crawl:server&apos;</span>);
<span class="hljs-keyword">const</span> {spawn}=<span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;child_process&apos;</span>);
<span class="hljs-keyword">let</span> app=express();
app.set(<span class="hljs-string">&apos;view engine&apos;</span>,<span class="hljs-string">&apos;html&apos;</span>);
app.set(<span class="hljs-string">&apos;views&apos;</span>,path.resolve(<span class="hljs-string">&apos;views&apos;</span>));
app.engine(<span class="hljs-string">&apos;html&apos;</span>,<span class="hljs-built_in">require</span>(<span class="hljs-string">&apos;ejs&apos;</span>).__express);
app.get(<span class="hljs-string">&apos;/&apos;</span>,<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">req,res</span>) </span>{
    <span class="hljs-keyword">let</span> {tagId}=req.query;
    <span class="hljs-keyword">let</span> tags=<span class="hljs-keyword">await</span> query(<span class="hljs-string">`SELECT * FROM tags`</span>);
    tagId=tagId||tags[<span class="hljs-number">0</span>].id;
    <span class="hljs-keyword">let</span> articles=<span class="hljs-keyword">await</span> query(<span class="hljs-string">`SELECT a.* from articles a inner join article_tag  t on a.id = t.article_id WHERE t.tag_id =? `</span>,[tagId]);
    res.render(<span class="hljs-string">&apos;index&apos;</span>,{
        tags,articles
    });
});
app.get(<span class="hljs-string">&apos;/detail/:id&apos;</span>,<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">req,res</span>) </span>{
    <span class="hljs-keyword">let</span> id=req.params.id;
    <span class="hljs-keyword">let</span> articles = <span class="hljs-keyword">await</span> query(<span class="hljs-string">`SELECT * FROM articles WHERE id=? `</span>,[id]);
    res.render(<span class="hljs-string">&apos;detail&apos;</span>,{<span class="hljs-attr">article</span>:articles[<span class="hljs-number">0</span>]});
});
app.listen(<span class="hljs-number">8080</span>);
<span class="hljs-keyword">let</span> job=<span class="hljs-keyword">new</span> CronJob(<span class="hljs-string">&apos;*/5 * * * *&apos;</span>,<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params"></span>) </span>{
    debug(<span class="hljs-string">&apos;&#x5F00;&#x59CB;&#x6267;&#x884C;&#x5B9A;&#x65F6;&#x4EFB;&#x52A1;&apos;</span>);
    <span class="hljs-keyword">let</span> update= spawn(process.execPath,[path.resolve(__dirname,<span class="hljs-string">&apos;update/index.js&apos;</span>)]);
    update.stdout.pipe(process.stdout);
    update.stderr.pipe(process.stderr);
    updaste.on(<span class="hljs-string">&apos;close&apos;</span>,<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">code</span>) </span>{
        <span class="hljs-built_in">console</span>.log(<span class="hljs-string">&apos;&#x66F4;&#x65B0;&#x4EFB;&#x52A1;&#xFF0C;&#x4EE3;&#x7801;=%d&apos;</span>,code);
    });
});
job.start();

process.on(<span class="hljs-string">&apos;uncaughtException&apos;</span>,<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">&apos;uncaughtException: %s&apos;</span>,erro.stack);
});
</code></pre>
<h3 id="t144.2 index.html">4.2 index.html <a href="#t144.2 index.html"> # </a></h3>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">%-</span> <span class="hljs-attr">include</span> <span class="hljs-attr">header.html</span>%&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;container&quot;</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;row&quot;</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;col-md-2&quot;</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;list-group&quot;</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">%tags.forEach(tag=</span>&gt;</span>{%&gt;
                   <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;list-group-item text-center&quot;</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/?tagId=&lt;%=tag.id%&gt;&quot;</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">style</span>=<span class="hljs-string">&quot;width:25px;height:25px;&quot;</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;&lt;%=tag.image%&gt;&quot;</span>/&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">%=tag.name%</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">%})%</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;col-md-10&quot;</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;list-group&quot;</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">%articles.forEach(article=</span>&gt;</span>{%&gt;
                   <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;list-group-item&quot;</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/detail/&lt;%=article.id%&gt;&quot;</span>&gt;</span>
                        <span class="hljs-tag">&lt;<span class="hljs-name">%=article.title%</span>&gt;</span>
                    <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                  <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
               <span class="hljs-tag">&lt;<span class="hljs-name">%})%</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">%-</span> <span class="hljs-attr">include</span> <span class="hljs-attr">footer.html</span>%&gt;</span>
</code></pre>
<h3 id="t154.3 detail.html">4.3 detail.html <a href="#t154.3 detail.html"> # </a></h3>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">%-</span> <span class="hljs-attr">include</span> <span class="hljs-attr">header.html</span>%&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;container&quot;</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;row&quot;</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;col-md-12&quot;</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;panel&quot;</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;panel-heading&quot;</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;text-center&quot;</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">%-</span> <span class="hljs-attr">article.title</span>%&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;panel-body&quot;</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">%-</span> <span class="hljs-attr">article.content</span>%&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">%-</span> <span class="hljs-attr">include</span> <span class="hljs-attr">footer.html</span>%&gt;</span>
</code></pre>
<h3 id="t164.4 header.html">4.4 header.html <a href="#t164.4 header.html"> # </a></h3>
<pre><code class="lang-html"><span class="hljs-meta">&lt;!DOCTYPE html&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">&quot;en&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">&quot;UTF-8&quot;</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;viewport&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;width=device-width, initial-scale=1.0&quot;</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">http-equiv</span>=<span class="hljs-string">&quot;X-UA-Compatible&quot;</span> <span class="hljs-attr">content</span>=<span class="hljs-string">&quot;ie=edge&quot;</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;stylesheet&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css&quot;</span> <span class="hljs-attr">integrity</span>=<span class="hljs-string">&quot;sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u&quot;</span> <span class="hljs-attr">crossorigin</span>=<span class="hljs-string">&quot;anonymous&quot;</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>&#x535A;&#x5BA2;&#x5217;&#x8868;<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;navbar navbar-default&quot;</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;container-fluid&quot;</span>&gt;</span>
    <span class="hljs-comment">&lt;!-- Brand and toggle get grouped for better mobile display --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;navbar-header&quot;</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;button&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;navbar-toggle collapsed&quot;</span> <span class="hljs-attr">data-toggle</span>=<span class="hljs-string">&quot;collapse&quot;</span> <span class="hljs-attr">data-target</span>=<span class="hljs-string">&quot;#bs-example-navbar-collapse-1&quot;</span> <span class="hljs-attr">aria-expanded</span>=<span class="hljs-string">&quot;false&quot;</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;sr-only&quot;</span>&gt;</span>Toggle navigation<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;icon-bar&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;icon-bar&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;icon-bar&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;navbar-brand&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;#&quot;</span>&gt;</span>&#x535A;&#x5BA2;&#x5217;&#x8868;<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>

    <span class="hljs-comment">&lt;!-- Collect the nav links, forms, and other content for toggling --&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;collapse navbar-collapse&quot;</span> <span class="hljs-attr">id</span>=<span class="hljs-string">&quot;bs-example-navbar-collapse-1&quot;</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;nav navbar-nav&quot;</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/&quot;</span>&gt;</span>&#x9996;&#x9875;<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><span class="hljs-comment">&lt;!-- /.navbar-collapse --&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span><span class="hljs-comment">&lt;!-- /.container-fluid --&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
</code></pre>
<h3 id="t174.5 footer.html">4.5 footer.html <a href="#t174.5 footer.html"> # </a></h3>
<pre><code class="lang-html"><span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<h3 id="t184.6 login.html">4.6 login.html <a href="#t184.6 login.html"> # </a></h3>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">%include</span> <span class="hljs-attr">header.html</span>%&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;row&quot;</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;col-md-4 col-md-offset-4&quot;</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">&quot;POST&quot;</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;email&quot;</span> <span class="hljs-attr">name</span>=<span class="hljs-string">&quot;email&quot;</span> <span class="hljs-attr">class</span>=<span class="hljs-string">&quot;form-control&quot;</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">&quot;&#x8BF7;&#x8F93;&#x5165;&#x90AE;&#x7BB1;&#x8FDB;&#x884C;&#x767B;&#x5F55;&quot;</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">%include</span> <span class="hljs-attr">footer.html</span>%&gt;</span>
</code></pre>
<h3 id="t194.7 subscribe.html">4.7 subscribe.html <a href="#t194.7 subscribe.html"> # </a></h3>
<pre><code class="lang-html">&lt;%include header.html%&gt;
    &lt;style&gt;
        .tag {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
        }
    &lt;/style&gt;
    &lt;div class=&quot;row&quot;&gt;
        &lt;form method=&quot;POST&quot;&gt;
            &lt;%
               for(let i=0;i&lt;tags.length;i++){
                   let tag = tags[i];
                   %&gt;
                &lt;div class=&quot;col-md-3 tag&quot;&gt;
                    &lt;img src=&quot;&lt;%=tag.image%&gt;&quot; /&gt;
                    &lt;p&gt;
                        &lt;%=tag.name%&gt;
                    &lt;/p&gt;
                    &lt;p&gt;
                        &lt;%=tag.subscribe%&gt;&amp;nbsp;&#x5173;&#x6CE8;&amp;nbsp;
                            &lt;%=tag.article%&gt;&amp;nbsp;&#x6587;&#x7AE0;
                    &lt;/p&gt;
                    &lt;div class=&quot;checkbox&quot;&gt;
                        &lt;label&gt;
                            &lt;input &lt;%=tag.subscribed? &quot;checked&quot;: &quot;&quot;%&gt; type=&quot;checkbox&quot; name=&quot;subscribe&quot; value=&quot;
                            &lt;%=tag.id%&gt;&quot;&gt; &#x5173;&#x6CE8;
                        &lt;/label&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
                &lt;%}
            %&gt;
                    &lt;input type=&quot;submit&quot; class=&quot;btn btn-primary&quot; /&gt;
        &lt;/form&gt;
    &lt;/div&gt;
    &lt;%include footer.html%&gt;
</code></pre>
<h2 id="t205. &#x8BA2;&#x9605;&#x53D1;&#x5E03;">5. &#x8BA2;&#x9605;&#x53D1;&#x5E03; <a href="#t205. &#x8BA2;&#x9605;&#x53D1;&#x5E03;"> # </a></h2>
<h3 id="t215.1 web/server.js">5.1 web/server.js <a href="#t215.1 web/server.js"> # </a></h3>
<pre><code class="lang-js">app.get(<span class="hljs-string">&apos;/login&apos;</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">req, res</span>) </span>{
    res.render(<span class="hljs-string">&apos;login&apos;</span>, { <span class="hljs-attr">title</span>: <span class="hljs-string">&apos;&#x767B;&#x5F55;&apos;</span> });
});
app.post(<span class="hljs-string">&apos;/login&apos;</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">req, res</span>) </span>{
    <span class="hljs-keyword">let</span> { email } = req.body;
    <span class="hljs-keyword">let</span> oldUsers = <span class="hljs-keyword">await</span> query(<span class="hljs-string">`SELECT * FROM users WHERE email=?`</span>, [email]);
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">Array</span>.isArray(oldUsers) &amp;&amp; oldUsers.length &gt; <span class="hljs-number">0</span>) {
        req.session.user = oldUsers[<span class="hljs-number">0</span>];
        res.redirect(<span class="hljs-string">&apos;/&apos;</span>);
    } <span class="hljs-keyword">else</span> {
        <span class="hljs-keyword">let</span> result = <span class="hljs-keyword">await</span> query(<span class="hljs-string">`INSERT INTO users(email) VALUES(?)`</span>, [email]);
        req.session.user = {
            <span class="hljs-attr">id</span>: result.insertId,
            email
        }
        res.redirect(<span class="hljs-string">&apos;/&apos;</span>);
    }
});
app.get(<span class="hljs-string">&apos;/subscribe&apos;</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">req, res</span>) </span>{
    <span class="hljs-keyword">let</span> tags = <span class="hljs-keyword">await</span> query(<span class="hljs-string">`SELECT * FROM tags`</span>);
    <span class="hljs-keyword">let</span> user = req.session.user;<span class="hljs-comment">//{id,name}</span>
    <span class="hljs-keyword">let</span> selectedTags = <span class="hljs-keyword">await</span> query(<span class="hljs-string">`SELECT tag_id from user_tag WHERE user_id = ?`</span>, [user.id]);
    <span class="hljs-keyword">let</span> selectTagIds = selectedTags.map(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> item[<span class="hljs-string">&apos;tag_id&apos;</span>]);
    tags.forEach(<span class="hljs-function"><span class="hljs-params">item</span> =&gt;</span> {
        item.checked = selectTagIds.indexOf(item.id) != <span class="hljs-number">-1</span> ? <span class="hljs-string">&apos;true&apos;</span> : <span class="hljs-string">&apos;false&apos;</span>;
    });
    res.render(<span class="hljs-string">&apos;subscribe&apos;</span>, { <span class="hljs-attr">title</span>: <span class="hljs-string">&apos;&#x8BF7;&#x8BA2;&#x9605;&#x4F60;&#x611F;&#x5174;&#x8DA3;&#x7684;&#x6807;&#x7B7E;&apos;</span>, tags });
});
app.post(<span class="hljs-string">&apos;/subscribe&apos;</span>, <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">req, res</span>) </span>{
    <span class="hljs-keyword">let</span> { tags } = req.body;<span class="hljs-comment">//[ &apos;1&apos;, &apos;2&apos;, &apos;9&apos; ] }</span>
    <span class="hljs-keyword">let</span> user = req.session.user;<span class="hljs-comment">//{id,name}</span>
    <span class="hljs-keyword">await</span> query(<span class="hljs-string">`DELETE FROM user_tag WHERE user_id=?`</span>, [user.id]);
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; tags.length; i++) {
        <span class="hljs-keyword">await</span> query(<span class="hljs-string">`INSERT INTO user_tag(user_id,tag_id) VALUES(?,?)`</span>, [user.id, <span class="hljs-built_in">parseInt</span>(tags[i])])
    }
    res.redirect(<span class="hljs-string">&apos;/&apos;</span>);
});
</code></pre>
<h3 id="t225.2 fromCodePoint">5.2 fromCodePoint <a href="#t225.2 fromCodePoint"> # </a></h3>
<p>String.fromCodePoint() &#x9759;&#x6001;&#x65B9;&#x6CD5;&#x8FD4;&#x56DE;&#x4F7F;&#x7528;&#x6307;&#x5B9A;&#x7684;&#x4EE3;&#x7801;&#x70B9;&#x5E8F;&#x5217;&#x521B;&#x5EFA;&#x7684;&#x5B57;&#x7B26;&#x4E32;&#x3002;</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> str = <span class="hljs-string">&apos;&amp;#x65F6&apos;</span>;
<span class="hljs-built_in">console</span>.log(<span class="hljs-built_in">String</span>.fromCodePoint(<span class="hljs-string">&apos;0x65F6&apos;</span>))
content = content.replace(<span class="hljs-regexp">/&amp;#x(\w+?);/g</span>, <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">matched, point</span>) </span>{
   <span class="hljs-keyword">return</span> <span class="hljs-built_in">String</span>.fromCodePoint(<span class="hljs-string">`0x<span class="hljs-subst">${point}</span>`</span>);
});
</code></pre>

        <div class="copyright">Powered by <a href="https://github.com/jaywcjlove/idoc" target="_blank">idoc</a>. Dependence <a href="https://nodejs.org">Node.js</a> run.</div>
    </div>
    
</div>

<script src="https://cdn.bootcss.com/jquery/3.0.0/jquery.js"></script>
<script>
$('.warpper .page-toc ul ul li a').on('click',function(){
  $('.warpper .page-toc ul ul li a').removeClass('my-active')
  $(this).addClass('my-active')
})
  // if (!$('.understand-me').length) {
  //   var bar = $(window).height() - $('.navbar ').height() - $('.page-toc').position().top;
  //   var count = bar / 26 / 2;
  //   var barHeight = $('.page-toc').outerHeight();
  //   $('.page-toc li').eq(0).children('a').addClass('red');
  //   var arr = [];
  //   $("h1,h2,h3,h4,h5,h6").each(function () {
  //     arr.push($(this).position().top);
  //   });
  //   var timer
  //   function dark() {
  //     clearTimeout(timer)
  //      timer = setTimeout(function () {
  //      var top = Math.abs($('.page-toc > ul').position().top);
  //      var cur = $('.content').scrollTop();
  //      for (var i = arr.length; i >= 0; i--) {
  //        if (arr[i] <= cur) {
  //          break;
  //        }
  //      }
  //      if (i === -1) {
  //        i = 0;
  //      }
  //      $('.page-toc li a').removeClass('red');
  //      $('.page-toc li').eq(i).children('a').addClass('red');
  //      let height = $('.page-toc li').eq(i).position().top-$('.page-toc').height(); // 如果当前的offset出去了 回到中间可好？
  //      $('.page-toc').scrollTop(height+$('.page-toc').height()/2);
  //    },200)
  //   }

  //   $('.content').on('scroll', dark);
  // }
</script>
<style>

    /* ::-webkit-scrollbar{width:14px;}
    ::-webkit-scrollbar-track{background-color:transparent;}
    ::-webkit-scrollbar-thumb{background-color:transparent;}
    ::-webkit-scrollbar-thumb:hover {background-color:transparent}
    ::-webkit-scrollbar-thumb:active {background-color:transparent} */

    .page-toc > ul .red {
        background: #f3f3f3;
        z-index: 1;
        border-left: 3px solid #009a61;
        -webkit-transition: all .2s ease;
        transition: all .2s ease;
        color: #000
    }





</style>
</body>
</html>
